package com.hankarun.gevrek.lib;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.net.nntp.Article;
import org.apache.commons.net.nntp.NNTPClient;
import org.apache.commons.net.nntp.NewsgroupInfo;
import org.apache.commons.net.nntp.SimpleNNTPHeader;
import org.apache.commons.net.nntp.Threader;
import org.apache.james.mime4j.codec.DecodeMonitor;
import org.apache.james.mime4j.codec.DecoderUtil;

import android.app.Application;
import android.util.Log;

public class ServerManager extends Application{
	private NNTPClient client;
	private String username;
	private String password;
	
	private String newsgroup;
	
	private List<ArrayList<Tuple2>> total;
	private List<ArrayList<Tuple2>> total1;
	
	public ArrayList<Tuple2> current;
	public Tuple2 carticle;
	
	public long getGroupCount(String _group,String _username, String _password){
		try {
			client.setSocketFactory(new MySSLSocketFactory());
			client.connect("news.ceng.metu.edu.tr",563);
			client.authenticate(_username, _password);
			client.group(_group);
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		String returns = client.getReplyString();
		String[] codes = returns.split(" ");
		long count = Long.parseLong(codes[3]);
		return count;
	}
	
	public void deleteArticle(Article article,String sender){
		checkConnect();
		SimpleNNTPHeader header;
        header = new SimpleNNTPHeader(article.getFrom(), "Cancel: "+article.getArticleId());
        header.addNewsgroup(newsgroup);
        header.addHeaderField("Control", "cancel "+article.getArticleId());
        header.addHeaderField("Sender", sender);
        try{
	        if (client.isAllowedToPost())
	        {
	            Writer writer = client.postArticle();
	
	            if (writer != null)
	            {
	                writer.write(header.toString());
	                writer.close();
	                client.completePendingCommand();
	            }
	        }
	        } catch(Exception e){
        }
	}
	
	public boolean postArticle(Article post, String body){
		checkConnect();
		SimpleNNTPHeader header;
        header = new SimpleNNTPHeader(post.getFrom(), post.getSubject());
        header.addNewsgroup(newsgroup);
        String[] refs = post.getReferences();
        if(refs.length > 0){
	        String ref = new String();
	        for(int x = 0; x < refs.length; x++)
	        	ref += refs[x] + " ";        
	        header.addHeaderField("References", ref.trim());
        }
        try{
	        if (client.isAllowedToPost())
	        {
	            Writer writer = client.postArticle();
	
	            if (writer != null)
	            {
	                writer.write(header.toString());
	                writer.write(body);
	                writer.close();
	                client.completePendingCommand();
	            }
	        }
	        } catch(Exception e){
        	return false;
        }
		return true;
	}
	
	
	public String getBody(String currentArticle){
		checkConnect();
		BufferedReader reader = null;
		String a = new String();
		try {
			reader = (BufferedReader) client.retrieveArticleBody(currentArticle);
            String line = reader.readLine();
            while (null != line) {
                a += line;
                line = reader.readLine();                
                a += "\n";
            }
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return a;		
	}
	
	public String getGroup(){
		return newsgroup;
	}
	
	public void setGroup(String _group){
		newsgroup = _group;
	}
	
    class Tuple{
    	public Long id;
    	public Date date;
    	public Tuple(long _id, Date _date){
    		id = _id;
    		date = _date;
    	}
    }
	
	public ArrayList<Tuple2> iterateArticles(){
		checkConnect();
        String fmt[];
        ArrayList<Tuple2> out = new ArrayList<Tuple2>();
		try {
			fmt = client.listOverviewFmt();
	        if (fmt != null) {	            
		        NewsgroupInfo group = new NewsgroupInfo();
		        client.selectNewsgroup(newsgroup, group);

		        long lowArticleNumber = group.getFirstArticleLong();
		        long highArticleNumber = lowArticleNumber + 5000;
		        
		        if(group.getArticleCountLong()>0){			       
			        Iterable<Article> articles1 = client.iterateArticleInfo(lowArticleNumber, highArticleNumber);

			        ArrayList<Tuple> tup = new ArrayList<Tuple>();
			        for(Iterator i = articles1.iterator();i.hasNext();) {
			        	Article a = (Article) i.next();
			        	Date date = null;
				        try {
				        	Locale locale = Locale.US;

				            DateFormat formatter = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z", locale);
				            date = (Date)formatter.parse(a.getDate());
				        } catch (ParseException e) {
				        }
			            tup.add(new Tuple(a.getArticleNumberLong(),date));
			         }
			        Collections.sort(tup, new Comparator<Tuple>() {
			        	  public int compare(Tuple o1, Tuple o2) {
			        	      if (o1.date == null || o2.date == null)
			        	        return 0;
			        	      return o2.date.compareTo(o1.date);
			        	  }
			        	});

			        
			        Iterable<Article> articles = client.iterateArticleInfo(lowArticleNumber, highArticleNumber);
			        Threader threader = new Threader();
			        Article root = (Article)threader.thread(articles);
			        	
			        total = new ArrayList < ArrayList <Tuple2> >();
			        total1 = new ArrayList< ArrayList <Tuple2 > >();
			        out.clear();
			        test(root, 0,out);

			        int s = 0;
			        for(Tuple tt : tup){
			        	for(ArrayList<Tuple2> ttu : total){
			        		for(Tuple2 ts : ttu){
			        			if(tt.id.equals(ts.article.getArticleNumberLong())){
			        				total1.add(ttu);
			        				total.remove(total.indexOf(ttu));
			        				s = 1;
			        				break;
			        			}			        			
			        		}
			        		if(s == 1){
			        			s = 0;
			        			break;
			        		}
			        	}
			        }
			        Log.d("Sort","gathered");
			        ArrayList<Tuple2> ret = new ArrayList<Tuple2>();
			        
					for(ArrayList<Tuple2> ts : total1){
						for(Tuple2 asd : ts){
							if(asd.article.getArticleNumberLong()!=-1)
								ret.add(asd);							
						}
					}

					current = new ArrayList<Tuple2>();
			        current.addAll(ret);
			        return ret;
		        }
		        return null;
		        
	        } else {

	        }
		} catch (IOException e) {

		}
		return null;
	}

	public void test(Article article, int depth, ArrayList<Tuple2> a){
		String sd = new String();
		if(depth!=0)
	        for (int i = 0; i < depth; ++i)
	            sd += ">";
	    if(article.getSubject()== null)
	    		article.setSubject("null");
	    
    	a.add(new Tuple2(article,sd));

	    if (article.kid != null) {
	        test(article.kid, depth + 1,a);
	    }
    	if(depth == 0){
    		total.add(a);
    		a = new ArrayList<Tuple2>();
    	}
	    if (article.next != null) {

	        test(article.next, depth,a);
	    }        
	}
	
	public List<String> listNewsGroups(){
		checkConnect();
		List<String> out = new ArrayList<String>();
        try {
			for(NewsgroupInfo n : client.iterateNewsgroups()) {
			    out.add(n.getNewsgroup());
			}
			return out;
		} catch (IOException e) {
			Log.e("ListGroups",e.getMessage());
		}
        return null;
	}
	
	private void checkConnect(){
		if(!client.isConnected()){
			connect();
		}
	}
	
    protected void onPause() {
        disconnect();
    }
    
    protected void onStop() {
        disconnect();
    }
	
    public void disconnect(){
    	try {
			client.disconnect();
		} catch (IOException e) {
			Log.e("server",e.getMessage());
		}
    }
	
	public int connect(){
		try {
			if(client.isConnected())
				client.disconnect();
			
			client.setSocketFactory(new MySSLSocketFactory());
			
			client.connect("news.ceng.metu.edu.tr",563);
		} catch (Exception e) {
			Log.e("Server Connection",e.getMessage());
			return -1;
		}
		try {
			if(!client.authenticate(username, password))
				return -2;
		} catch (IOException e) {
			Log.e("Authentication",e.getMessage());
		}
		return 0;
	}
	
	@Override
	public void onCreate(){
		client = new NNTPClient();
	}
	
	public void setAuth(String _user, String _pass){
		username = _user;
		password = _pass;
	}
	
	
	public static class MySSLSocketFactory extends SSLSocketFactory {

		private final SSLContext sslContext = SSLContext.getInstance("TLS");

		public MySSLSocketFactory() throws Exception {

			TrustManager[] trustAllCerts = new TrustManager[]{
	    		    new X509TrustManager() {
	    		        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
	    		            return null;
	    		        }
	    		        public void checkClientTrusted(
	    		            java.security.cert.X509Certificate[] certs, String authType) {
	    		        }
	    		        public void checkServerTrusted(
	    		            java.security.cert.X509Certificate[] certs, String authType) {
	    		        }
	    		    }
	    		};
			sslContext.init(null, trustAllCerts, null);
		}

		public SSLContext getSllContext() {
			return sslContext;
		}

		@Override
		public Socket createSocket(Socket socket, String host, int port,
				boolean autoClose) throws IOException, UnknownHostException {
			Socket result = sslContext.getSocketFactory().createSocket(socket,
					host, port, autoClose);
			//log.debug("Configuring SSLSocket for SSLv3 protocol only");
			((SSLSocket) result).setEnabledProtocols(new String[] { "SSLv3" });
			((SSLSocket) result).setUseClientMode(true);
			return result;
		}

		@Override
		public Socket createSocket() throws IOException {
			Socket result = sslContext.getSocketFactory().createSocket();
			//log.debug("Configuring SSLSocket for SSLv3 protocol only");
			((SSLSocket) result).setEnabledProtocols(new String[] { "SSLv3" });
			((SSLSocket) result).setUseClientMode(true);
			return result;
		}

		@Override
		public String[] getDefaultCipherSuites() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public String[] getSupportedCipherSuites() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public Socket createSocket(String host, int port)
				throws IOException, UnknownHostException {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public Socket createSocket(InetAddress host, int port)
				throws IOException {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public Socket createSocket(String host, int port,
				InetAddress localHost, int localPort) throws IOException,
				UnknownHostException {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public Socket createSocket(InetAddress address, int port,
				InetAddress localAddress, int localPort) throws IOException {
			// TODO Auto-generated method stub
			return null;
		}
	}
}
